package com.dh.test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;

public class SocketSCMode {

	public static void main(String[] args) throws Exception {
		SocketSCMode leo = new SocketSCMode();
		leo.exe();
	}

	public void exe() throws InterruptedException {
		Thread server = new Thread(new ServerMsg());
		Thread client = new Thread(new ClientMsg1());
		server.start();
		Thread.sleep(100);
		client.start();
	}

}

class ClientMsg1 implements Runnable {
	@Override
	public void run() {
		try {
			SocketChannel socket = SocketChannel.open();
			socket.connect(new InetSocketAddress("127.0.0.1", 9999));
			socket.configureBlocking(false);
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			while (true) {
				String datestr = format.format(new Date());
				ByteBuffer buff = ByteBuffer.wrap(datestr.getBytes());
				// logger.info("Sending the message " + datestr);
				socket.write(buff);
				Thread.sleep(2000);
			}
		} catch (IOException | InterruptedException ie) {
			ie.printStackTrace();
		}
	}
}

class ServerMsg implements Runnable {
	@Override
	public void run() {

		try {
			//ServerSocketChannel是一个可以监听新进来的TCP连接的通道，就像标准IO中的ServerSocket一样。
			// 获得一个ServerSocket通道
			ServerSocketChannel serverChannel = ServerSocketChannel.open();
			ServerSocket socket = serverChannel.socket();
			socket.bind(new InetSocketAddress(9999));
			
			//设置通道为非阻塞
			serverChannel.configureBlocking(false);
			//通过调用Selector.open()方法创建一个Selector，如下： 
			Selector selector = Selector.open();
			/*
				向Selector注册通道 
				与Selector一起使用时，Channel必须处于非阻塞模式下。
				这意味着不能将FileChannel与Selector一起使用，
				因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。 
				
				注意register()方法的第二个参数。这是一个“interest集合”，
				意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件： 
				Connect 连接就绪
				Accept  接收就绪
				Read    读就绪
				Write   写就绪
			 */
			//如果你对不止一种事件感兴趣，那么可以用“位或”操作符将常量连接起来，如下：
			//int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
			SelectionKey serverKey = serverChannel.register(selector, SelectionKey.OP_ACCEPT);
			
			/**
			 * interest集合
			 */
			//interestSet集合是你所选择的感兴趣的事件集合
			int interestSet = serverKey.interestOps();
			boolean isInterestedInAccept  = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;
			System.out.println("-------------------"+isInterestedInAccept);
			
			/**
			 * reday集合
			 * ready 集合是通道已经准备就绪的操作的集合。在一次选择(Selection)之后，
			 * 你会首先访问这个ready set。Selection将在下一小节进行解释。可以这样访问ready集合： 
			 */
			int readySet = serverKey.readyOps(); 
			
			System.out.println(serverKey.isAcceptable());  
			System.out.println(serverKey.isConnectable());  
			System.out.println(serverKey.isReadable());  
			System.out.println(serverKey.isWritable());
			
			long flag = 1L;

			while (true) {
				int count = selector.select();
				if (count > 0) {
					Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
					while (iter.hasNext()) {
						SelectionKey key = iter.next();
						System.out.println("Flag-->" + flag + "   The interest is " + key.interestOps());
						if (key.isAcceptable()) {
							System.out.println("Flag-->" + flag + "   The server accept one requesting");
							iter.remove();
							ServerSocketChannel server = (ServerSocketChannel) key.channel();
							SocketChannel client = server.accept();
							client.configureBlocking(false);
							client.register(selector, SelectionKey.OP_READ);
						} else if (key.isReadable()) {
							iter.remove();
							System.out.println("Flag-->" + flag + "   Reading the mesage");
							SocketChannel client = (SocketChannel) key.channel();
							ByteBuffer buff = ByteBuffer.allocate(1024);
							int len = client.read(buff);
							if (len > 0 && buff.hasArray()) {
								byte[] arr = buff.array();
								String msg = new String(arr, 0, len);
								System.out.println("Flag-->" + flag + "   The recevied message is " + msg);
							}
						}
					}
				}
				flag++;
			}
		} catch (IOException ie) {
			ie.printStackTrace();
		}
	}
}
